home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 25
/
Cream of the Crop 25.iso
/
bbs
/
doorinfo.zip
/
DOORUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-14
|
20KB
|
937 lines
/*
** This set of functions is a 'standard' collection of I/O routines
** for Falken doors authors.
**
** --------------------------------------------------------------------
**
** Compile Options (MSC 5.1 and above)
** cl /AL /c /Gs doorutil.c
**
** Compile and link a door program -
** cl /AL /c /Gs doorprog.c
** link doorprog doorutil lmtc;
**
**
** The purpose of these functions is to make the mechanics of
** interfacing with Falken as transparent as possible.
**
** Each function is documented with a comment block preceeding
** the function.
**
** The header file DOORUTIL.H contains function prototypes.
**
** Global Variables -
**
** Certain variables are defined in these routines, and have Global
** scope. These variables are used by these functions, and may be
** used by your program, provided their values are not changed.
**
** int who; which line the user is logged onto
** int inq; message queue for in-bound messages
** int outq; message queue for out-bound messages
** int numlines; number of lines on this Falken system
** acctp *acct; pointer to array of account structures
** userp *user; pointer to array of user structures
** struct acct_rec *myacct; pointer to THIS users account structure
** struct user_rec *myuser; pointer to THIS users user structure
** struct msg3 m3; initialization message structure
** struct msg1 *m1; general purpose message queue pointer
** char workbuf[1300]; common area for message transfers
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <dos.h>
#include <ctype.h>
#include "doorutil.h" /* function prototypes */
#include "c:\mt\tcb.h"
int isinstalled(void);
struct msg3 m3;
/*
** m1 is a pointer to a structure used for passing text between us
** and Falken
*/
struct msg1 *m1;
/*
** m4 is a pointer to a structure used by Falken to tell us how many
** bytes are available in the output buffer.
*/
struct msg4 *m4;
struct msg5 *m5;
struct msg6 *m6;
struct msg7 *m7;
/*
** cbr is a structure used when making database calls to Falken.
** Doors have the ability to manipulate Falkens databases, but
** must call Falken to do it. This structure is set up for the
** database call, and then the address of this structure is passed
** to Falken in the mdbs structure below.
*/
struct call_bt_rec cbr;
struct mdbs_rec mdbs;
/*
** Workbuf is a character array used for intertask communications.
** All the structure pointers above (m1, m4), are loaded with
** the address of workbuf,making it a common memory region for
** intertask communication.
*/
unsigned char workbuf[1400];
int inq, outq, who, numlines; /* see header comments above */
struct acct_rec far *acct;
struct user_rec far *user;
struct cfg_rec far *cfg; /* pointer to BBSCFG record */
/*
** acct and user are useful, giving us the address of the structure arrays.
** for simplified access, though, we will set up a pointer to OUR
** element in the array.
**
** myacct-> will be the account record for the current user
** myuser-> will be the user record for the current user
*/
struct acct_rec far *myacct;
struct user_rec far *myuser;
struct tcb_rec far *tcb;
int Mytcbnum;
message_out(int queue, void *b, int count)
{
while (send_md_msg(queue, b, count) == -1)
{
delay(2);
}
}
int a_exit(int code)
{
exit(code);
}
int check_tcb_names(char *name)
{
int j;
for (j = 0; j < maxtasks; j++)
{
if ((strcmp(tcb[j].tcbname, name) == 0) &&
(tcb[j].cur_state != st_free))
{
break;
}
}
if(j==maxtasks) return 0;
else return 1;
}
int set_tcb_name(char *name)
{
strcpy(tcb[Mytcbnum].tcbname, name);
}
int isinstalled()
{
union REGS ir;
ir.h.ah = 0x80; /* test for cswitch installed. */
int86(0x21, &ir, &ir);
if (ir.x.ax == 0x1956)
return ir.x.bx; /* it is installed, return version number */
return 0;
}
int init()
{
time_t t1;
if (isinstalled() == 0)
{
puts("Falken BBS not running.");
a_exit(0);
}
Mytcbnum = get_tcb_info(&tcb);
get_tcb_address(&tcb);
m1 = (struct msg1 *) workbuf; /* set up the working buffer */
m4 = (struct msg4 *) workbuf;
m5 = (struct msg5 *) workbuf;
m6 = (struct msg6 *) workbuf;
m7 = (struct msg7 *) workbuf;
m3.type = 0;
t1 = time(NULL) + 20L;
/*
** Wait 20 seconds for the initialization message to come.
** This is gross overkill, since it will be here almost instantaniously
** if it is coming.
*/
do
{
if (t1 < time(NULL))
{
a_exit(0); /* waited too long for init message */
}
if (testmsg(1))
{
recvmsg(1, &m3, sizeof(struct msg3));
if (m3.type == 8)
a_exit(0);
}
relinq(); /* nothing to do for now... give up time
* slice */
} while (m3.type != 7);
/*
** m3 is volatile. It is a pointer to a block of memory that will be
** reused frequently. Save the important information into our global
** variables.
*/
who = m3.line;
inq = m3.inq;
outq = m3.outq;
numlines = m3.numlines;
user = m3.userptr;
acct = m3.acctptr;
cfg = m3.cfgptr;
myacct = &acct[who];
myuser = &user[who];
return who; /* return the line number this user is on. */
}
/*
** If something drastic has happened, and it is necessary to not only
** terminate the door, but to log this user off, call logoff().
*/
void logoff(int who)
{
m1->type = 5;
m1->count = who;
message_out(0, workbuf, 4);
}
/*
** setbinarymode() places the user's port into binary mode.
** it will then be up to the door to handle all I/O via FOSSIL calls.
** All of Falken's amenities, such as character echo, word wrap, input
** filtering, and all that will be gone.
**
** This is useful for file transfer protocols, or for hot-key type
** menus.
*/
void setbinarymode(int who)
{
m1->type = 8;
m1->count = who;
message_out(0, workbuf, 4);
}
/*
** settextmode() returns the line to text mode, where the door must use
** message queues for communciation.
** The Falken I/O controls will become active again.
*/
void settextmode(int who)
{
m1->type = 7;
m1->count = who;
message_out(0, workbuf, 4);
}
/*
** clear_input_buffer() and clear_output_buffer() instruct Falken to
** remove all bytes from the input and output buffers, respectively,
** for this port.
*/
void clear_input_buffer(int who)
{
m1->type = 13;
m1->count = who;
message_out(0, workbuf, 4);
}
void clear_output_buffer(int who)
{
m1->type = 14;
m1->count = who;
message_out(0, workbuf, 4);
}
/*
** Do not use this call under normal circumstances.
** Use get_port() to gain control of ANOTHER serial port from Falken.
** This disables logins on that port. This is used for the dial-out
** function.
*/
void get_port(int port)
{
m1->type = 19;
m1->count = port;
message_out(0, workbuf, 4);
}
/*
** Give the second port back to Falken with return_port().
*/
void return_port(int port)
{
m1->type = 20;
m1->count = port;
message_out(0, workbuf, 4);
}
/*
** get_oba() returns the number of bytes available in the user's
** output buffer.
*/
int get_oba()
{
m4->type = 12;
message_out(outq, workbuf, 2);
do
{
recvmsg(inq, workbuf, sizeof(struct msg4));
if (m1->type == 8)
a_exit(0);
} while (m1->type != 6);
return m4->oba;
}
/*
** get_in_cnt() returns the number of bytes waiting in the user's
** input buffer. Falken will buffer the input until the user has
** pressed ENTER, at which time the entire buffer will be sent to
** the door on the message queue.
*/
int get_in_cnt()
{
m1->type = 9;
message_out(outq, workbuf, 2);
do
{
recvmsg(inq, workbuf, sizeof(struct msg1));
if (m1->type == 8)
a_exit(0);
} while (m1->type != 5);
return m1->count;
}
/*
** bbslog() sends a string to the Falken log file, and displays it on
** the Falken sysop screen.
*/
int bbslog(char *fs)
{
int j;
strcpy(m1->text, fs);
m1->count = who;
m1->type = 18;
j = strlen(m1->text);
message_out(0, workbuf, j + 5);
relinq(); /* give the bbs a chance to log it */
return (j);
}
/*
** lprintf does much the same thing, but it uses a format string
** ala printf().
*/
void lprintf(char *fs,...)
{
va_list argptr;
int j;
va_start(argptr, fs);
vsprintf(m1->text, fs, argptr);
va_end(argptr);
m1->count = who;
m1->type = 18;
j = strlen(m1->text);
message_out(0, workbuf, j + 5);
}
/*
** qprintf() is just like printf(), except it sends the output to the
** users line instead of the local screen.
*/
int qprintf(char *fs,...)
{
int j;
va_list argptr;
va_start(argptr, fs);
vsprintf(m1->text, fs, argptr);
va_end(argptr);
m1->count = who;
m1->type = 1;
j = strlen(m1->text);
message_out(0, workbuf, j + 5);
return (j);
}
int qnprintf(int who, char *fs,...)
{
int j;
va_list argptr;
va_start(argptr, fs);
vsprintf(m1->text, fs, argptr);
va_end(argptr);
m1->count = who;
m1->type = 1;
j = strlen(m1->text);
message_out(0, workbuf, j + 5);
return (j);
}
/*
** qputs() sends a line of text to the user's line. A newline is appended
** to the text, just like puts()
*/
int qputs(char *fs)
{
int j;
strcpy(m1->text, fs);
strcat(m1->text, "\r");
m1->count = who;
m1->type = 1;
j = strlen(m1->text);
message_out(0, workbuf, j + 5);
return (j);
}
/*
** send() is the same as qputs(), but does not append a newline to the
** text.
*/
int send(char *fs)
{
int j;
int br_array[2];
if ((j = strlen(fs)) > 1000)
{
br_array[0] = who;
br_array[1] = 0xff;
broadcast(fs, br_array);
}
else
{
strcpy(m1->text, fs);
m1->count = who;
m1->type = 1;
message_out(0, workbuf, j + 5);
}
return (j);
}
int sendtoline(int w, char *fs)
{
int j;
int br_array[2];
if ((j = strlen(fs)) > 1000)
{
br_array[0] = w;
br_array[1] = 0xff;
broadcast(fs, br_array);
}
else
{
strcpy(m1->text, fs);
m1->count = w;
m1->type = 1;
message_out(0, workbuf, j + 5);
}
return (j);
}
/*
** Broadcast means to send to multiple lines.
** The line numbers to receive the text are contained in an array
** of integers, terminated with an 0xff.
*/
void broadcast(char *fs, int *linenums)
{
int flg;
int j;
j = 0;
while ((j < numlines) && (linenums[j] != 0xff))
{
m5->sendto[j] = linenums[j];
j++;
}
m5->sendto[j] = 0xff;
m5->text = (char far *) fs;
m5->flag = (int far *) &flg;
m5->type = 33;
m5->tcbnum = Mytcbnum;
flg = 0;
message_out(0, m5, sizeof(struct msg5));
while (flg == 0)
relinq();
}
void sendmsg(int who, int msgnum)
{
m6->m6line = who;
m6->m6type = 29;
m6->m6msgnum = msgnum;
message_out(0, m6, sizeof(struct msg6));
}
void getmsg(int ansiflag, int msgnum, char *fs)
{
int flg;
m6->m6text = (char far *) fs;
m6->m6flag = (int far *) &flg;
m6->m6ansiflag = ansiflag;
m6->m6type = 30;
m6->m6msgnum = msgnum;
m6->m6tcbnum = Mytcbnum;
flg = 0;
message_out(0, m6, sizeof(struct msg6));
do
{
relinq();
} while (flg == 0);
}
/*
** qgets() is the alternative to gets(). It reads a line of input from
** the user. The line is truncated to 'len' bytes, and is nul-terminated.
** The number of bytes read is returned.
*/
int qgets(char *s, int len)
{
do
{
recvmsg(inq, workbuf, sizeof(struct msg1));
if (m1->type == 8)
a_exit(0);
} while (m1->type != 1);
if (strlen(m1->text) > len)
{
m1->text[len] = '\0'; /* force truncation */
}
strcpy(s, m1->text);
return (strlen(s));
}
/*
** tqgets() is the same as qgets(), plus a timeout value. If no
** text is received before 'timeout' seconds pass, then an error is
** returned.
*/
int tqgets(char *s, int len, int timeout)
{
time_t t1, t2;
t1 = time(NULL);
t2 = t1 + (long) timeout;
while (t1 < t2)
{
if (testmsg(inq))
{
recvmsg(inq, workbuf, sizeof(struct msg1));
if (m1->type == 8)
{
a_exit(0);
}
if (m1->type == 1)
{
if (strlen(m1->text) > len)
{
m1->text[len] = '\0'; /* force truncation */
}
strcpy(s, m1->text);
return strlen(s);
}
}
relinq();
t1 = time(NULL);
}
return -1; /* return timeout error. */
}
/*
** waitforempty() does just that. It does not return to the caller
** until the user's output buffer is empty.
*/
void waitforempty()
{
while (get_oba() < 16384)
{
relinq();
}
}
/*
** This function returns the serial number of the Falken system
** in use.
*/
int getserialnum(char *s)
{
time_t t1;
m1->type = 15; /* get Falken serial number */
message_out(outq, workbuf, 2);
t1 = time(NULL) + 10; /* wait 5 seconds */
do
{
if (testmsg(inq))
{
recvmsg(inq, workbuf, 200);
if (m1->type == 8)
{
a_exit(0);
}
}
else if (time(NULL) > t1)
{
m1->type = 9;
m1->text[0] = '\0';
}
else
{
relinq();
}
} while (m1->type != 9);
strcpy(s, m1->text);
return strlen(s);
}
/*
** This function returns the version number of the Falken system
** in use.
*/
int getversion(char *s)
{
time_t t1;
m1->type = 25; /* get Falken version number */
message_out(outq, workbuf, 2);
t1 = time(NULL) + 5; /* wait 5 seconds */
do
{
if (testmsg(inq))
{
recvmsg(inq, workbuf, 200);
if (m1->type == 8)
{
a_exit(0);
}
}
else if (time(NULL) > t1)
{
m1->type = 11;
m1->text[0] = '\0';
}
else
{
relinq();
}
} while (m1->type != 11);
strcpy(s, m1->text);
return strlen(s);
}
/*
** BTRV is a routine to access database records from within a door.
** Paramaters are the same as calling BTRV normally, except the
** file ID is an integer, used to identify which file we want to
** access, rather than a pointer to an IX_DESC variable.
**
** See the database documentation for more details, and when using
** this function to access the databases ... BE CAREFUL!
*/
int btrv(int op, int file_id, void *addr, int *len, ENTRY * key, int keynum)
{
int done;
cbr.bt_file_id = file_id;
cbr.data_addr = (void far *) addr;
cbr.length = (int far *) len;
cbr.data_key = (ENTRY far *) key;
cbr.keynumber = keynum;
cbr.bt_function = op;
mdbs.mdbs_type = 28; /* new style database service */
mdbs.cbraddr = &cbr;
mdbs.tcbnum = Mytcbnum;
mdbs.doneflag = &done;
done = 0;
message_out(0, &mdbs, sizeof(struct mdbs_rec));
while (!done)
relinq();
return cbr.rtnvalue;
}
/*
** Set the users page length to 'lines'.
** Lines = 0 to stop paging. (the annoying 'Press ENTER to continue'.
*/
void btupag(int lines)
{
m6->m6type = 31;
m6->m6line = who;
m6->m6msgnum = lines;
message_out(0, m6, sizeof(struct msg6));
}
/*
** Tell Falken to monitor CD (non-0), or not monitor CD (0)
** on the given line.
*/
void setwatchdog(int lines, int value)
{
if (value)
m6->m6type = 35;
else
m6->m6type = 36;
m6->m6line = who;
message_out(0, m6, sizeof(struct msg6));
}
/*
** set echo,
** 0 = echo off, 1 = echo on, 2 = echo dots
*/
void btuech(int echoval)
{
m6->m6type = 32;
m6->m6line = who;
m6->m6msgnum = echoval;
message_out(0, m6, sizeof(struct msg6));
}
/*
** Reads an account record whose name or account number is in s1,
** load the account record into mem.
*/
int find_account(char *s1, void *mem)
{
ENTRY acctkey;
int j;
char s[uidlen];
strncpy(s, s1, uidlen - 1);
s[uidlen - 1] = '\0'; /* force a string at most uidlen-1 bytes */
strcpy(acctkey.key, s); /* try account number */
j = sizeof(struct acct_rec); /* just need to read a handle */
if (btrv(b_getequ, ACCT_NUM_FILE, mem, &j,
&acctkey, 0) == OK)
{ /* user id is in the account file */
strcpy(s, mem); /* found an account number */
}
strcpy(acctkey.key, s);
j = sizeof(struct acct_rec);
return btrv(b_getequ, ACCT_FILE, mem, &j, &acctkey, 0);
}
/*
** Start a door, and wait for it to finish, then return to the caller.
*/
int start_a_door(char *cmd, int pri)
{
int j, k;
char old_name[10];
j = load_a_door(cmd, pri);
if (j >= 0)
{
strcpy(old_name, myuser->doors_id);
for (k = 0; k < 9 && cmd[k] && cmd[k] != ' '; k++)
{
myuser->doors_id[k] = cmd[k];
}
myuser->doors_id[k] = '\0';
wait_for_door(j);
strcpy(myuser->doors_id, old_name);
}
return j;
}
/*
** Wait until the tcb indicated returns to a free state
** meaning the task has terminated.
*/
void wait_for_door(int tcbnum)
{
while (tcb[tcbnum].cur_state != st_free)
relinq();
}
/*
** Load a door, returning a number < 0 if error.
** Returns the task number (TCB number) if successful
*/
int load_a_door(char *cmd, int pri)
{
int j;
char junk[30];
char b[10];
for (j = 0; j < 9 && cmd[j] && cmd[j] != ' '; j++)
{
b[j] = cmd[j];
}
b[j] = '\0';
hog();
while (testmsg(1) != 0)
{
relinq();
}
message_out(1, &m3, sizeof(struct msg3));
sprintf(junk, "Starting door : %s", b);
bbslog(junk);
j = loadtask(cmd, pri, 1);
if (j == 1)
{
while ((j = get_load_status()) == 0)
relinq();
}
else
{
j = -1;
}
if (j < 0)
{
recvmsg(1, junk, 1); /* pull the init event off. */
}
nohog();
return j;
}
/*
** Save the user's account record to disk.
*/
void save_acct()
{
m1->count = who;
m1->type = 22;
message_out(0, workbuf, 4);
}
/*
** sendtoq() is the same as send(),
** but sends to a particular queue
*/
int sendtoq(char *fs, int qnum)
{
int j;
j = strlen(fs);
strcpy(m1->text, fs);
m1->count = who;
m1->type = 1;
message_out(qnum, workbuf, j + 5);
return (j);
}
/*
** Find the user whose name matches the character string supplied.
** The character string may have data behind it (.sayto, etc),
** so do a limited compare based on the length of the user name.
** Choose the longest name, and only match if the text string
** supplied has a non-alphanumeric character where the name
** would end.
*/
int finduser(char *t, char **ptr)
{
int i, j, k, l;
if (isdigit(*t))
{
k = atoi(t);
if ((k < 0) || (k >= numlines))
k = -1;
while (isdigit(*t))
t++;
while (isspace(*t))
t++;
*ptr = t;
}
else
{
for (i = l = 0; i < numlines; i++)
{
j = strlen(acct[i].acctname);
if ((user[i].u_stat != st_idle) && (!isalnum(t[j])) &&
(strnicmp(t, acct[i].acctname, j) == 0) && (j > l))
{
l = j;
k = i;
}
}
if (l == 0)
k = -1; /* didn't find a match */
else
{
t += strlen(acct[k].acctname);
while (isspace(*t))
t++;
*ptr = t;
}
}
return k;
}